﻿using System;
using System.Collections.Generic;
using UniRx;
using UnityEngine;

/// <summary>
/// 基于状态机的AI基类
/// </summary>
public abstract partial class AIBase : UnitComponentBase
{
    /// <summary>
    /// AI名
    /// </summary>
    public string name => m_Name ?? (m_Name = getName);
    protected abstract string getName { get; }
    private string m_Name;


    /// <summary>
    /// 当前状态
    /// </summary>
    public AIStateBase currentState { get => m_CurrentState.Value; set => m_CurrentState.Value = value; }
    private ReactiveProperty<AIStateBase> m_CurrentState = new ReactiveProperty<AIStateBase>();
    public IObservable<AIStateBase> onStateChanged => m_CurrentState;


    /// <summary>
    /// AI输出
    /// </summary>
    public AIOutput outputs => m_Outputs ?? CreateOutputs();

    private AIOutput m_Outputs;
    protected virtual void InitOutputs() { }
    private AIOutput CreateOutputs()
    {
        m_Outputs = new AIOutput();
        InitOutputs();
        return m_Outputs;
    }


    private Dictionary<string, AIStateBase> m_StateDict = new Dictionary<string, AIStateBase>();
    private AIStateBase m_EntryState;
    private List<AITransition> m_Transitions = new List<AITransition>();
    private List<AITransition> m_GlobalTransitions = new List<AITransition>();
    private List<AITransition> m_ActiveTransitions = new List<AITransition>();
    private IDisposable m_ExecuterSubscriber;
    private List<IDisposable> m_ConditionSubscribers = new List<IDisposable>();
    private List<IDisposable> m_GlobalConditionSubscribers = new List<IDisposable>();


    protected override void OnInit()
    {
        CreateOutputs();
    }

    protected override void OnSpawn()
    {
        StartAI();
    }

    protected override void OnDespawn()
    {
        StopAI();
    }

    protected override void OnThaw()
    {
        StartAI();
    }

    protected override void OnFreeze()
    {
        StopAI();
    }

    /// <summary>
    /// 注册状态
    /// </summary>
    protected void RegisterState(AIStateBase state, bool isEntry = false)
    {
        if (m_StateDict.ContainsKey(state.name))
        {
            Debug.LogError($"AI状态注册失败：状态 {state.name} 已在AI {name} 中注册，请勿重复注册");
            return;
        }
        m_StateDict.Add(state.name, state);
        state.ai = this;
        if (isEntry && m_EntryState == null)
        {
            m_EntryState = state;
        }
        state.Init();
    }

    /// <summary>
    /// 注册过渡
    /// </summary>
    protected void RegisterTransition(AIStateBase source, AIStateBase target, Func<bool> condition, float fade = 0f)
    {
        RegisterTransition(source, target, null, condition, fade);
    }

    /// <summary>
    /// 注册过渡
    /// </summary>
    protected void RegisterTransition(AIStateBase source, AIStateBase target, IObservable<Unit> stream = null, Func<bool> condition = null, float fade = 0f)
    {
        var transition = new AITransition();
        transition.source = source;
        transition.target = target;
        if (stream != null)
            transition.stream = stream;
        else
            transition.stream = entity.lifeCycle.GetLifeCycleStream(UnitLifeCycle.LifeType.AICondition).AsUnitObservable();
        if (condition != null)
            transition.condition = condition;
        transition.fade = fade;
        RegisterTransition(transition);
    }

    private void RegisterTransition(AITransition transition)
    {
        if (m_Transitions.Exists(transition.Equals))
        {
            Debug.LogError($"状态机过渡注册失败：已存在完全相同的过渡 source:{transition.source} target:{transition.target}，请勿重复注册");
            return;
        }
        m_Transitions.Add(transition);
    }

    /// <summary>
    /// 注册全局过渡
    /// </summary>
    protected void RegisterGlobalTransition(AIStateBase target, IObservable<Unit> stream = null, Func<bool> condition = null)
    {
        var transition = new AITransition();
        transition.target = target;
        if (stream != null)
            transition.stream = stream;
        else
            transition.stream = entity.lifeCycle.GetLifeCycleStream(UnitLifeCycle.LifeType.AICondition).AsUnitObservable();
        if (condition != null)
            transition.condition = condition;
        RegisterGlobalTransition(transition);
    }

    private void RegisterGlobalTransition(AITransition transition)
    {
        if (m_GlobalTransitions.Exists(transition.Equals))
        {
            Debug.LogError($"状态机过渡注册失败：已存在完全相同的全局过渡 target:{transition.target}，请勿重复注册");
            return;
        }
        m_GlobalTransitions.Add(transition);
    }

    /// <summary>
    /// 启动AI
    /// </summary>
    public void StartAI()
    {
        if (m_StateDict.Count <= 0)
        {
            Debug.LogError($"AI启动失败：AI {name} 未添加任何状态");
            return;
        }
        if (entity == null)
        {
            Debug.LogError($"AI启动失败：AI {name} 未设置依赖组件");
            return;
        }
        if (m_EntryState == null)
        {
            Debug.LogError($"AI启动失败：AI {name} 未设置初始状态");
            return;
        }
        m_GlobalTransitions.Sort(TransitionSortRule);
        RegisterGlobalTransitionConditions();
        EnterState(m_EntryState.name);
    }

    /// <summary>
    /// 终止AI（状态指向null）
    /// </summary>
    public void StopAI()
    {
        if (currentState == null) return;
        currentState.Exit();
        currentState = null;
        UnregisterTransitionConditions();
        UnregisterGlobalTransitionConditions();
        m_ExecuterSubscriber?.Dispose();
        m_ActiveTransitions.Clear();
        outputs.Reset();
    }

    private void EnterState(string stateName, float fade = 0f)
    {
        if (m_StateDict.ContainsKey(stateName))
        {
            EnterState(m_StateDict[stateName], fade);
            return;
        }
        Debug.LogError($"AI切换状态失败：状态 {stateName} 未在AI {name} 中注册");
    }

    private void EnterState(AIStateBase state, float fade = 0f)
    {
        if (!m_StateDict.ContainsKey(state.name))
        {
            Debug.LogError($"AI切换状态失败：状态 {state.name} 未在AI {name} 中注册");
            return;
        }
        // 退出当前状态
        if (currentState != null)
        {
            currentState.Exit();
            UnregisterTransitionConditions();
        }
        // 切换状态
        currentState = state;
        // 订阅新状态 executer
        m_ExecuterSubscriber?.Dispose();
        m_ExecuterSubscriber = currentState.updateStream
            .WhenActive(entity.gameObject)
            .Subscribe(_ => currentState.Execute())
            .AddTo(entity);
        // 更新当前激活的 transition
        m_ActiveTransitions.Clear();
        for (int i = 0; i < m_Transitions.Count; i++)
        {
            var transition = m_Transitions[i];
            if (m_Transitions[i].source != currentState) continue;
            m_ActiveTransitions.Add(m_Transitions[i]);
        }
        m_ActiveTransitions.Sort(TransitionSortRule);
        RegisterTransitionConditions();
        currentState.Enter();
    }

    private void RegisterGlobalTransitionConditions()
    {
        for (int i = 0; i < m_GlobalTransitions.Count; i++)
        {
            var transition = m_GlobalTransitions[i];
            var disposable = transition.stream
                .WhenActive(entity.gameObject)
                .Where(_ => currentState != null && CheckTransitionTriggered(transition))
                .Subscribe(_ => EnterState(transition.target, transition.fade))
                .AddTo(entity);
            m_GlobalConditionSubscribers.Add(disposable);
        }
    }

    private void UnregisterGlobalTransitionConditions()
    {
        for (int i = 0; i < m_GlobalConditionSubscribers.Count; i++)
        {
            m_GlobalConditionSubscribers[i]?.Dispose();
        }
        m_GlobalConditionSubscribers.Clear();
    }

    private void RegisterTransitionConditions()
    {
        currentState.isEnd = false;
        for (int i = 0; i < m_ActiveTransitions.Count; i++)
        {
            var transition = m_ActiveTransitions[i];
            var disposable = transition.stream
                .WhenActive(entity.gameObject)
                .Where(_ => CheckTransitionTriggered(transition))
                .Subscribe(_ => EnterState(transition.target, transition.fade))
                .AddTo(entity);
            m_ConditionSubscribers.Add(disposable);
        }
    }

    private void UnregisterTransitionConditions()
    {
        for (int i = 0; i < m_ConditionSubscribers.Count; i++)
        {
            m_ConditionSubscribers[i]?.Dispose();
        }
        m_ConditionSubscribers.Clear();
    }

    private int TransitionSortRule(AITransition x, AITransition y)
    {
        return y.priority.CompareTo(x.priority);
    }

    private bool CheckTransitionTriggered(AITransition transition)
    {
        if (currentState.isLoop)
        {
            return transition.condition == null || transition.condition.Invoke();
        }
        else
        {
            return (transition.target.priority > currentState.priority || currentState.isEnd) && (transition.condition == null || transition.condition.Invoke());
        }
    }
}